package cn.edu.wzu.openlearning.service;

import cn.edu.wzu.openlearning.mapper.WordMapper;
import cn.edu.wzu.openlearning.pojo.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpSession;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

@Transactional
@Service
public class WordService {
    @Autowired
    private WordMapper wordMapper;

    /**
     * 利用PageInfo分页单词书
     * @param start
     * @param sizeByOnePage
     * @return
     */
    public PageInfo<Word> listWordDict(int start, int sizeByOnePage){
        PageHelper.startPage(start,sizeByOnePage);
        List<Word> wordDict = wordMapper.selectWordDict();
        return new PageInfo<Word>(wordDict);
    }

    /**
     * 查询单词
     * @param word
     * @return
     */
    public Word selectWord(String word){
        return wordMapper.selectWord(word);
    }

    /**
     * 异步处理上传的单词书文件
     * @param fileStream
     * @param bookNickname
     * @param session
     */
    @Async
    public void handleFileChangeUserWordBook(InputStream fileStream, String bookNickname, HttpSession session){
        String bookTableName = null;
        UserWordBooks wordBooks = null;
        try {
            // 用户检测
            User user = (User) session.getAttribute("user");
            if (user == null)
                throw new Exception("用户没有登录不能上传文件");
            // 单词检测
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileStream));
            String word;

            Set<String> wordsSet = new HashSet<>();
            while ((word = bufferedReader.readLine()) != null) {
                word = word.trim();
                if(isPhonticName(word)){
                    wordsSet.add(word);
                }
            }
            if(wordsSet.isEmpty())
                throw new Exception("没有单词");
            // 需要去重
            List<String> words = new LinkedList<>(wordsSet);
            // 已经去重了
            List<Word> matchingWord = wordMapper.selectMatchingWords(words);
            if(matchingWord.isEmpty())
                throw new Exception("没有匹配的单词");
            String uuid = UUID.randomUUID().toString().replaceAll("-","");
            bookTableName = "wordbook"+"_"+uuid;
            wordBooks = new UserWordBooks(null,user.getUserId(),bookNickname, bookTableName);
            // 先注册
            wordMapper.createUserWordBook(wordBooks);
            // 创建表
            wordMapper.createWordBookByUUid(bookTableName);
            // BUG: set global max_allowed_packet = 2*1024*1024*10;
            wordMapper.insertWordInWorkBook(bookTableName, matchingWord);
            // 处理完成
            List<Map<String,String>> names = (List<Map<String, String>>) session.getAttribute("names");
            for (Map<String,String> map:
                    names) {
                String nickname = map.get("nickname");
                if (nickname.equalsIgnoreCase(bookNickname)){
                    map.put("value","true");
                }

            }
        } catch (Exception e) {
            List<Map<String,String>> names = (List<Map<String, String>>) session.getAttribute("names");
            for (Map<String,String> map:
                    names) {
                String nickname = map.get("nickname");
                if (nickname.equalsIgnoreCase(bookNickname)){
                    map.put("value","lose");
                }
            }
            try {
                // 删除刚刚创建的空的表格
                wordMapper.deleteTableByWordBookNameAndUUid(bookTableName);
                // 删除总表 立刻对 新建表格的管理
                wordMapper.deleteUserWordBook(wordBooks);
            } catch (Exception newErr) {
                newErr.printStackTrace();
            }
            throw new RuntimeException(e);
        }
    }

    /**
     *  获取用户的设置环境，如果没有则创建
     * @param user
     * @return
     */
    public WordReciteSetting getWordSettingByUser(User user){
        WordReciteSetting setting = wordMapper.selectWordReciteSettingByUserId(user.getUserId());
        if (setting == null){
            wordMapper.insertWordReciteSettingByUserId(user.getUserId());
            setting = wordMapper.selectWordReciteSettingByUserId(user.getUserId());
        }
        return setting;
    }


    /**
     * 查询所有的单词书
     */
    public List<QueryWordBooks> listWordBooks(HttpSession session){
        User user = (User) session.getAttribute("user");
        List<QueryWordBooks> queryWordBooksList = wordMapper.listUserWordBooks();
        for (QueryWordBooks queryWordBooks : queryWordBooksList){
            // 设置单词书现有的数量
            queryWordBooks.setWordCount(wordMapper.countWordNumber(queryWordBooks.getUserWordBooks().getBookUuid()));
            queryWordBooks.setUserRecitedWordCount(
                    wordMapper.countUserRecitedWordNumber(queryWordBooks.getUserWordBooks().getBookUuid(),user.getUserId())
            );
        }
        return queryWordBooksList;
    }

    /**
     * 更新单词书的设置
     * @param seed
     * @param recite_num
     * @param bookId
     * @param userId
     * @return
     */
    public Integer alterWordReciteSettingByUserId(
            String seed,
            Integer recite_num,
            String bookId,
            Integer userId){
        return wordMapper.alterWordReciteSettingByUserId(seed,recite_num,bookId,userId);
    }

    /**
     * 查询生单词
     *   1. 查询一下单词熟悉度表中是否有单词熟悉度为0的单词，且是否当前数量 now_word_num 等于**设置的背诵数量**
     *   2. **如果数量不够，** 通过与词典外键构建新的单词书（seed排序）得到table_word_book_1(twb1)，
     *   在twb1按顺序找还没有背诵的单词
     *   `（select * twb1 where twb1.word not in (select t1.word_id from 单词熟悉度表 t1 where user_id = 当前用户) ）`
     *   ，中选择**设置的背诵数量-now_word_num**的单词插入到单词熟悉度表中，熟悉度设置为0
     *   3. 将生单词放入session中，**并记录生单词的数量（打卡表使用）**
     *   4. 返回记忆单词页面，等待用户下一步操作。
     *  @return
     */
    public List<Word> selectRawWords(User user){
        // 查询一下单词熟悉度表中是否有单词熟悉度为0的单词
        List<Word> rawZeroWords = wordMapper.selectWordByFamiliarityEqZero(user.getUserId());
        // 查询当前设置的背诵数量
        WordReciteSetting setting = wordMapper.selectWordReciteSettingByUserId(user.getUserId());
        // 还需要的数量
        int stillNeededNumber = setting.getReciteNum() - rawZeroWords.size();
        // 是否当前数量 now_word_num 大于等于**设置的背诵数量
        if (stillNeededNumber <= 0){
            // 数量足够
            return rawZeroWords;
        } else {
            // 数量不够，找一些 (找还没有背诵的单词)
            List<Word> additionalWords = wordMapper.selectRawWord(setting.getUseWordBookUuid(), user.getUserId(), setting.getSeed(), stillNeededNumber);
            if ( additionalWords!=null && !additionalWords.isEmpty()){
                //  将这些 additionalWords 添加到熟悉度中，熟悉度设置为0
                Integer integer = wordMapper.insertRawWordToWordFamiliarity(user.getUserId(), additionalWords);
            }
            //  然后 合并 单词列表并返回
            rawZeroWords.addAll(additionalWords);
        }
        return rawZeroWords;
    }

    /**
     * 查询熟单词
     * 我们要在trb1中找单词，必须符合如下条件：
     *   1. 熟悉度为1的单词，最后更新时间是1天前的
     *   2. 熟悉度为2的单词，最后更新时间是2天前的
     *   3. ...
     *   4. 熟悉度为7的单词，最后更新时间是60天前的
     * @param user
     * @return
     */
    public List<Word> selectFamiliarWords(User user){
        // 查询当前设置
        WordReciteSetting setting = wordMapper.selectWordReciteSettingByUserId(user.getUserId());
        int stillNeededNumber = setting.getReciteNum() * 7;
        List<Word> familiarWords = new ArrayList<>();
        int[] fLs = new int[]{1,2,4,7,15,30,60}; // 熟悉度
        for(int i=0;i<fLs.length; i++){
            if(familiarWords.size()<stillNeededNumber){
                List<Word> wordList = wordMapper.selectFamiliarWords(setting.getUseWordBookUuid(),
                        user.getUserId(), setting.getSeed(), i+1, fLs[i] , stillNeededNumber);
                familiarWords.addAll(wordList);
                stillNeededNumber -= wordList.size();
            }
        }
        return familiarWords;
    }

    /**
     * 这些词都是存在记录的！
     * 生词 全部设置为1
     * Easy 词全部设置为7
     * 熟词忘记了，设置为1  其他熟词增加1
     * 增加打卡记录
     * @param session
     */
    public void wordReciteClockIn(HttpSession session){
        User user = (User) session.getAttribute("user");

        List<Word> step1RawWordList = (List<Word>) session.getAttribute("step1RawWordList");
        if(step1RawWordList==null)
            step1RawWordList = new ArrayList<>();
        List<Word> step3familiarWords = (List<Word>) session.getAttribute("step3familiarWords");
        if(step3familiarWords==null)
            step3familiarWords = new ArrayList<>();
        int step3Size = step3familiarWords.size();

        Set<Word> wordEasyList = (Set<Word>) session.getAttribute("wordEasyList");
        Set<Word> wordForget = (Set<Word>) session.getAttribute("wordForget");

        // 生词 全部设置为 1
        if (!step1RawWordList.isEmpty())
            wordMapper.updateWordsFamiliarity(step1RawWordList,user.getUserId(),1);
        // Easy 全部设置为 7
        if (!wordEasyList.isEmpty())
            wordMapper.updateWordsFamiliarity(wordEasyList,user.getUserId(),7);
        // 熟词忘记 设置为 1
        if (!wordForget.isEmpty())
            wordMapper.updateWordsFamiliarity(wordForget,user.getUserId(),1);
        // 其他熟词增加 1
        step3familiarWords.removeAll(wordForget);
        // 其他熟词增加 1 ，如果熟词已经是7了，则不能在增加，只更新时间
        if (!step3familiarWords.isEmpty())
            wordMapper.updateAddOneWordsFamiliarity(step3familiarWords,user.getUserId());
        // 打卡
        wordMapper.insertUserWordClockInHistroy(user.getUserId(),step1RawWordList.size(),step3Size,wordForget.size());

    }

    public void clearUserRecitedWord(Boolean allClear,User user){
        WordReciteSetting setting = wordMapper.selectWordReciteSettingByUserId(user.getUserId());
        if(allClear){
            wordMapper.clearAllUserRecitedWord(user.getUserId());
        } else {
            String bookUuid = setting.getUseWordBookUuid();
            if(bookUuid != null)
                wordMapper.clearUserRecitedWord(bookUuid,user.getUserId());
        }
    }











    /**
     * 判断字符串中是否含有英文
     * @param str
     * @return 包含返回true
     */
    public boolean isPhonticName(String str) {
        char[] chars=str.toCharArray();
        boolean isPhontic = false;
        for(int i = 0; i < chars.length; i++) {
            isPhontic = (chars[i] >= 'a' && chars[i] <= 'z') ||
                    (chars[i] >= 'A' && chars[i] <= 'Z') ||
                    chars[i] == ' ' ||
                    chars[i] == '-' ||
                    chars[i] == '.';
            if (!isPhontic) {
                return false;
            }
        }
        return true;
    }
}
